package final$finally$finalize区别.final关键字;

import lombok.Data;

import java.lang.reflect.Field;

@Data
public class FinalFieldDemo {
    // 在定义时初始化属性的值
    private final String name = "name";
    // 在构造方法中赋值
    private final String address;
    // 绕过jvm优化（将字符串变成常量值）
    private static final String phone = (null == null ? "phone" : "");

    public FinalFieldDemo(String address) {
        this.address = address;
    }

    // 通过反射机制，可以破坏final的规则。
    public static void main(String[] args) throws Exception {
        FinalFieldDemo demo = new FinalFieldDemo("address");
        //输出初始化值
        System.out.println(demo.name);
        Field name = demo.getClass().getDeclaredField("name");
        name.setAccessible(true);
        name.set(demo, "name02");
        // 输出的是修改后的值
        System.out.println(name.get(demo));
        // 输出的是修改前的值
        /*原因是：JVM在编译时期做的深度优化机制, 就把final类型的String进行了优化,
                在编译时期就会把String处理成常量，导致打印结果不会发生变化。*/
        System.out.println(demo.getName());
        //*************解决办法*****************
        //输出初始化值
        System.out.println(demo.getAddress());
        Field address = demo.getClass().getDeclaredField("address");
        address.setAccessible(true);
        address.set(demo, "address02");
        // 输出的是修改后的值
        System.out.println(demo.getAddress());
        // 反射无法修改被final和static同时修饰的变量，可以通过反射先去掉final关键字，然后就可以修改了
    }


    // 为什么局部内部类和匿名内部类只能访问final变量

    /**
     * test方法中，有可能test方法执行结束且a和b的声明周期也结束了，
     * 但是Thread这个匿名内部类可能还未执行完，那么在Thread中的run方法中继续使用局部变量a和b就会有问题。
     * 但是又要实现这样的效果，怎么办呢？所以Java采用了复制的手段来解决这个问题。
     */
    public void test(final int b) {
        final int a = 10;
        new Thread() {
            @Override
            public void run() {
                System.out.println(a);
                System.out.println(b);
            }
        }.start();
    }

}
